package XNAT::Config;

use strict;
#use XNAT::DefaultConfig;
use Carp qw( croak cluck confess );


=head1 XNAT::Config

XNAT::Config - an object for reading and writing XNAT configuration files.

=head2 EXAMPLE USAGE

 my $xconf = XNAT::Config->new();

 or

 my $xconf = XNAT::Config->new('host');

=head2 METHODS

=over 4

=cut

=item XNAT::Config->new()

=item XNAT::Config->new('host')

Create a new XNAT::Config object, and get information from the configuration file. The default configuration is specified in the XNAT::DefaultConfig file, which you'll have to edit if you would like change the default settings.

The configurations are loaded in the following order with each subsequent config file "overwritting" any variables set in the previous one:

=over

The defaults in XNAT::DefaultConfig.

The user's ~/xnat.d/xnat.conf file.

The host.conf file (if specified). We search for this first in the current working directory, then in the ~/.xnat.d/ directory, otherwise we exit non-zero with an error.

=back

=cut

sub new {
  my $class = shift;
  my $self = {};
  $self->{host} = shift if @_;
  confess "ERROR: Wrong number of arguments to XNAT::Config->new();! Expected none or one!\n" if @_;
  bless $self,$class;
  $self->{values} = {};
  $self->{_loadedConfigFiles} = [];
  if (-e "$ENV{HOME}/.xnat.d/xnat.conf") {
    $self->_loadConfigFromFile("$ENV{HOME}/.xnat.d/xnat.conf");
  } else {
    # Debug info
    print "DEBUG: No $ENV{HOME}/.xnat.d/xnat.conf found.\n" if $main::verbose > 2;
    # No config file. If there is no host either, we prompt to create one.
    if(! $self->{values}->{host} && ! $self->{values}->{error}) {
      # TO-DO: Ask if the user want to create one.
    }
  }
  $self;
}

# Private method, used for loading config files.
sub _loadConfigFromFile {
  my $self = shift;
  my $configFile = shift;
  push @{$self->{_loadedConfigFiles}}, $configFile;
  if (-e $configFile) {
    print "DEBUG: FOUND $configFile, will load.\n" if $main::verbose > 1;
    open(CONF,"<$configFile") ||
      confess "ERROR: Unable to open '$configFile' for reading!\nREASON: $!\n";
    my $section = 'default';
    my $line_number = 0;
    while ( my $line = <CONF> ) {
      $line_number ++;
      chomp($line);
      # Skip blank lines.
      next unless $line;
      # Skip comments
      next if $line =~ m{^\s+#};
      # Get variables (strip starting and trailing whitespace)
      if($line =~ m{\s*(\S.*)\s*=\s*(.*?)\s*$}) {
	my ($key,$value) = ($1,$2);
	if('host' eq $key) {
	  # Debug
	  $section = $value;
	  print "DEBUG: Starting section '$section', line $line_number '$configFile'\n" if $main::verbose > 1;
	  $self->{values}->{$section} = {} unless $self->{values}->{$section};
	  next;
	} else {
	  $self->{values}->{$section}->{$key} = $value;
	}
      } else {
	warn "WARNING: Did not understand line $line_number in $configFile, ignoring." if  $main::verbose > 1;
      }
    }
    close CONF;
    $self->_loadVarsForSection($self->host);
  }
}

sub _loadVarsForSection {
  my $self = shift;
  my $sectionName = $self->{host} || 'default';
  print "DEBUG: Looking for section '$sectionName' in '",join("', '",@{$self->{_loadedConfigFiles}}),"'.\n" if $main::verbose > 2;
  my $found = 0;
  # If this section is defined in the defaults, make a copy of the name/value pairs.
  # Need to make a copy and not use a pointer, otherwise we'll be overwriting the defaults.
  if ($self->{values}->{$sectionName}) {
    print "DEBUG: Found it!\n" if $main::verbose > 2;
    $self->{host} = $sectionName;
    $self->{url} = $self->{values}->{$sectionName}->{url};
    if(! $self->{url}) {
      warn "WARNING: No 'url' defined for section '$sectionName' in '",join("', '",@{$self->{_loadedConfigFiles}}),"'!\n" if $main::verbose > 0;
    }
    $self->{login} = $self->{values}->{$sectionName}->{login};
    if(! $self->{login}) {
      warn "WARNING: No 'login' defined for section '$sectionName' in '",join("', '",@{$self->{_loadedConfigFiles}}),"'!!\n" if $main::verbose > 0;
    }
    $self->{pass} = $self->{values}->{$sectionName}->{pass};
    if(! $self->{pass}) {
      warn "WARNING: No 'pass' defined for section '$sectionName' in '",join("', '",@{$self->{_loadedConfigFiles}}),"'!!\n" if $main::verbose > 0;
    }
  } else {
    print "WARNING: Could not find section '$sectionName' in '",join("', '",@{$self->{_loadedConfigFiles}}),"'.\n" if $main::verbose > 0;
  }
}

=item $xconf->host()

Get the XNAT "host", where "host" is the shorthand alias for the host. Used to store information in the config file.

=item $xconf->host('host')

Set the "host" for use in this session. This will mean that the values in the "host" section of config files will be used. Returns the previous host setting.

=cut

sub host {
  my $self = shift;
  if(@_) {
    my $host = $self->{host};
    $self->{host} = shift;
    $self->_loadVarsForSection();
    $host;
  } else {
    $self->{host};
  }
}

=item $xconf->url()

Get the XNAT "url", where "url" is the shorthand alias for the url. Used to store information in the config file.

=item $xconf->url('url')

Set the "url" for use in this session. This will mean that the values in the "url" section of config files will be used. Returns the previous url setting.

=cut

sub url {
  my $self = shift;
  if(@_) {
    my $url = $self->{url};
    $self->{url} = shift;
    $url;
  } else {
    $self->{url};
  }
}

=item $xconf->login()

=item $xconf->login('login')

Get or set the XNAT login.

=cut

sub login {
  my $self = shift;
  if(@_) {
    my $login = $self->{login};
    $self->{login} = shift;
    $login;
  } else {
    $self->{login};
  }
}

=item $xconf->user()

See $xconf->login();

=cut

sub user { login(@_); }

=item $xconf->pass()

=item $xconf->pass('pass')

Get or set the XNAT password.

=cut

sub pass {
  my $self = shift;
  if(@_) {
    my $pass = $self->{pass};
    $self->{pass} = shift;
    $pass;
  } else {
    $self->{pass};
  }
}

=item $xconf->password()

See $xconf->pass();

=cut

sub password { pass(@_); }


1;
__END__
